package com.plm.k8s.myk8sapi.cmd;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RuntimeUtil;
import com.plm.k8s.myk8sapi.pojo.entity.node.ApiNodeEntity;
import com.plm.k8s.myk8sapi.util.MyBeanUtil;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import java.io.File;
import java.io.FileWriter;
import java.util.List;
import java.util.Map;

/**
 * 本地命令调用
 * @author 潘磊明
 * 版本号：1.0
 * 创建日期：2021/7/14 9:37
 */
@Data
public abstract class AbstractLocalCmd implements ICmd {

    // kube客户端路径
    @Value("${k8s.api.kubectlPath}")
    protected String kubectlPath;

    // kubeConfig文件
    @Value("${k8s.api.kubeConfig}")
    protected String kubeConfig;

    // yaml文件的输出父目录
    @Value("${k8s.api.yamlParentPath}")
    protected String yamlParentPath;

    protected final String CMD_DELIMITER = " "; // 命令分隔符

    @Override
    public String exec(String... cmd) {
        return RuntimeUtil.execForStr(cmd);
    }

    @Override
    public List<String> execForLine(String... cmd) {
        List<String> list = RuntimeUtil.execForLines(cmd);
        return list;
    }

    @Override
    public <T> T execForYamlObject(String cmd, Class<T> clazz) throws Exception {
        String yamlStr = exec(cmd);
        return load(yamlStr, clazz);
    }

    @Override
    public String applyYamlFile(File file) throws Exception {
        return applyYamlFile(file, true);
    }

    @Override
    public String applyYamlFile(File file, boolean isDelete) throws Exception {
        if (!(isYamlFile(file))) throw new Exception("文件不是yaml文件");
        String cmd = generateApplyFileCmd(file.getAbsoluteFile());
        String result = exec(cmd);
        if (isDelete) file.delete();
        return result;
    }

    /**
     * 生成kubectl apply -f filename命令
     * @param absoluteFile
     * @return
     */
    protected String generateApplyFileCmd(File absoluteFile) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("apply -f ").append(absoluteFile);
        return sb.toString();
    }

    @Override
    public String deleteYamlFile(File file) throws Exception {
        return deleteYamlFile(file, true);
    }

    @Override
    public String deleteYamlFile(File file, boolean isDelete) throws Exception {
        if (!(isYamlFile(file))) throw new Exception("文件不是yaml文件");
        String cmd = generateDeleteFileCmd(file.getAbsoluteFile());
        String result = exec(cmd);
        if (isDelete) file.delete();
        return result;
    }

    /**
     * 生成kubectl delete -f filename
     * @param absoluteFile
     * @return
     */
    protected String generateDeleteFileCmd(File absoluteFile) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("delete -f ").append(absoluteFile);
        return sb.toString();
    }

    /**
     * 将实体类转换成yaml文件
     * @param obj
     * @return
     */
    protected File transferObject2YamlFile(Object obj) throws Exception {
        Yaml yaml = new Yaml();
        Map<String, Object> map = MyBeanUtil.bean2Map(obj);
        File yamlFile = new File(yamlParentPath + IdUtil.randomUUID() + ".yaml");
        if (!yamlFile.exists()) yamlFile.createNewFile();
        FileWriter fileWriter = new FileWriter(yamlFile);
        yaml.dump(map, fileWriter);
        fileWriter.close();
        return yamlFile;
    }

    /**
     * 验证是否是yaml文件
     * @param file
     * @return
     */
    protected boolean isYamlFile(File file) {
        return file != null && file.isFile() && "yaml".equals(FileUtil.extName(file));
    }

    /**
     * 生成基础的kubectl命令
     * @return
     */
    protected String generateKubeCmdBase() {
        StringBuilder sb = new StringBuilder();
        if (StringUtils.hasText(kubectlPath)) {
            sb.append(kubectlPath);
            sb.append("/");
        }
        sb.append("kubectl");
        sb.append(CMD_DELIMITER);
        if (StringUtils.hasText(kubeConfig)) {
            sb.append("--kubeconfig");
            sb.append(CMD_DELIMITER);
            sb.append(kubeConfig);
            sb.append(CMD_DELIMITER);
        }
        return sb.toString();
    }

    protected void addNamespace(StringBuilder sb, String namespace) {
        if (!StringUtils.hasText(namespace)) return;
        sb.append(CMD_DELIMITER).append("-n ").append(namespace);
    }

    protected void addNameFilter(StringBuilder sb, String nameFilter) {
        if (!StringUtils.hasText(nameFilter)) return;
        sb.append(CMD_DELIMITER);
        sb.append("--field-selector metadata.name=");
        sb.append(nameFilter);
    }

    protected void addLabelFilter(StringBuilder sb, Map<String, String> labelFilter) {
        if (CollectionUtil.isEmpty(labelFilter)) return;
        sb.append(CMD_DELIMITER).append("-l ");
        for (Map.Entry<String, String> entry : labelFilter.entrySet()) {
            sb.append(entry.getKey());
            sb.append("=");
            sb.append(entry.getValue());
            sb.append(",");
        }
        sb = sb.deleteCharAt(sb.length() - 1);
    }

    /**
     * 将yaml装载成对象
     * @param yamlStr
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T>T load(String yamlStr, Class<T> clazz) throws Exception {
        Yaml yaml = new Yaml(new Constructor(ApiNodeEntity.class));
        Map<String, Object> nodeMap = yaml.loadAs(yamlStr, Map.class);
        T object = clazz.newInstance();
        BeanUtil.copyProperties(nodeMap, object);
        return object;
    }

    /**
     * 替换换行符
     * @param str
     * @return
     */
    protected String trimBr(String str) {
        return str.replaceAll("[\\f\\n\\r]", "");
    }
}
